package com.usefullc.user.service.interceptor;

import com.usefullc.common.constants.SystemConstant;
import com.usefullc.common.enums.AppTypeEnum;
import com.usefullc.common.enums.YesNoEnum;
import com.usefullc.common.exception.BizException;
import com.usefullc.common.user.OnlineUser;
import com.usefullc.common.user.OnlineUserManager;
import com.usefullc.common.util.MapUtils;
import com.usefullc.system.service.AbstractService;
import com.usefullc.system.service.component.SystemConfigComponent;
import com.usefullc.system.service.interceptor.AspectProcess;
import com.usefullc.user.domain.AuthRes;
import com.usefullc.user.domain.Role;
import com.usefullc.user.query.AuthResQuery;
import com.usefullc.user.query.RoleQuery;
import com.usefullc.user.service.AuthResService;
import com.usefullc.user.service.RoleService;
import com.usefullc.user.service.UserService;
import com.usefullc.user.service.component.UserManager;
import com.usefullc.user.vo.UserVo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

//import com.usefullc.user.service.RoleAuthResService;

/**
 * @author: Sampson
 * @date: 2022-01-10 13:44
 */
@Component
public class AuthAspectProcess extends AbstractService implements AspectProcess {

    @Value("${usefullc.auth.check}")
    private boolean authCheck;

    @Autowired
    private UserService userService;

    @Autowired
    private AuthResService authResService;

    @Autowired
    private RoleService roleService;

//    @Autowired
//    private RoleAuthResService roleAuthResService;

    @Autowired
    private SystemConfigComponent systemConfigComponent;

    private Map<Long, Set<AuthResObj>> roleAuthResMap = new HashMap<>();
    private Map<String, AuthResObj> riskUrlAuthResMap = new HashMap<>();
    private Map<String, AuthResObj> repeatUrlAuthResMap = new HashMap<>();
    private Set<String> whiteUrls = new HashSet<>();


    @EventListener(ApplicationReadyEvent.class)
    public void initData() {
        roleAuthResMap.clear();
        //获取所有可用资源
        AuthResQuery authResQuery = new AuthResQuery();
//        String appName = systemConfigComponent.getAppName();
        List<String> appTypeList = new ArrayList<>();
//        appTypeList.add(appName);
        for (AppTypeEnum value : AppTypeEnum.values()) {
            appTypeList.add(value.getCode());
        }
//        appTypeList.add(AppTypeEnum.USER.getCode());
        authResQuery.setAppTypeList(appTypeList);
        authResQuery.setStatus(YesNoEnum.YES.getCode());
        List<AuthRes> authResList = authResService.findAll(authResQuery);

        if (CollectionUtils.isEmpty(authResList)) {
            return;
        }
        Map<Long, AuthResObj> authResMap = authResList.stream().filter(x -> x.getAuthCheck()).collect(Collectors.toMap(AuthRes::getId, authRes -> {
            AuthResObj authResObj = new AuthResObj();
            authResObj.setCode(authRes.getCode());
            authResObj.setUrl(authRes.getUrl());
            return authResObj;
        }));


        riskUrlAuthResMap = authResList.stream().filter(x -> x.getRiskCheck()).collect(Collectors.toMap(AuthRes::getUrl, authRes -> {
            AuthResObj authResObj = new AuthResObj();
            authResObj.setCode(authRes.getCode());
            authResObj.setUrl(authRes.getUrl());
            authResObj.setRiskCheck(authRes.getRiskCheck());
            authResObj.setRiskCheckCondition(authRes.getRiskCheckCondition());
            return authResObj;
        }));

        repeatUrlAuthResMap = authResList.stream().filter(x -> x.getRepeatCheck()).collect(Collectors.toMap(AuthRes::getUrl, authRes -> {
            AuthResObj authResObj = new AuthResObj();
            authResObj.setCode(authRes.getCode());
            authResObj.setUrl(authRes.getUrl());
            authResObj.setRiskCheck(authRes.getRepeatCheck());
            return authResObj;
        }));

        whiteUrls = authResList.stream().filter(x -> !x.getAuthCheck()).map(x -> x.getUrl()).collect(Collectors.toSet());

        //手动加入
        whiteUrls.add("/user/user/getImgCode");
        whiteUrls.add("/user/c/getImgCode");
        whiteUrls.add("/user/c/getSmsCode");
        whiteUrls.add("/user/c/login");
        whiteUrls.add("/user/c/register");
        whiteUrls.add("/user/c/getLoginUserInfo");
//        whiteUrls.add("/user/user/login");
//        whiteUrls.add("/user/user/logout");
//        whiteUrls.add("/system/common/res");
        whiteUrls.add("/tools/initData");
        whiteUrls.add("/task/test");
        whiteUrls.add("swagger-ui.html");
        whiteUrls.add("/swagger-resources");
        whiteUrls.add("v2/api-docs");
        whiteUrls.add("/liveStatus");
        whiteUrls.add("/readyStatus");
        whiteUrls.add("/redirectHttpStatus");
//        whiteUrls.add("/user/authRes/getAuthResByCurrentUser");


        //建立角色资源对应关系
//        RoleAuthResQuery roleAuthResQuery = new RoleAuthResQuery();

        List<Role> roleList = roleService.findAll(new RoleQuery());
        if (CollectionUtils.isNotEmpty(roleList)) {
            List<AuthRes> dataList = new ArrayList<>();
            for (Role role : roleList) {
                List<AuthRes> authResDBList = roleService.getBaseMapper().findAuthResListByRoleId(role.getId());
                if (CollectionUtils.isEmpty(authResDBList)) {
                    continue;
                }
//                List<AuthRes> resList = role.getAuthResList();
//                if (CollectionUtils.isEmpty(resList)) {
//                    continue;
//                }
                for (AuthRes authRes : authResDBList) {
                    if (!dataList.contains(authRes)) {
                        MapUtils.putSetElement(roleAuthResMap, role.getId(), authResMap.get(authRes.getId()));
                    }
                }
            }
        }

//        //排序
//        Collections.sort(dataList, Comparator.comparingInt(AuthRes::getOrderNo));
//        for (AuthRes authRes : dataList) {
//            MapUtils.putSetElement(roleAuthResMap,roleId,authResMap.get(authResId));
//        }
//        List<RoleAuthRes> roleAuthResList = roleAuthResService.findAll(roleAuthResQuery);
//        if (CollectionUtils.isEmpty(roleAuthResList)) {
//            return;
//        }
//        for (RoleAuthRes roleAuthRes : roleAuthResList) {
//            Long roleId = roleAuthRes.getRoleId();
//            Long authResId = roleAuthRes.getAuthResId();
//            AuthResObj authResObj = authResMap.get(authResId);
//            if(authResObj == null){
//                continue;
//            }
//
//        }
    }

    public boolean checkAuth(String requestURI,UserVo user) {
        try {
            if(StringUtils.containsIgnoreCase(requestURI,"/system/common/res")){
                requestURI = "/system/common/res";
            }
            //白名单
            if (whiteUrls.contains(requestURI)) {
                return true;
            }
            String finalRequestURI = requestURI;
            boolean isMatch = whiteUrls.stream().filter(x -> x.endsWith("*")).anyMatch(x -> finalRequestURI.matches(x));
            if(isMatch){
                return true;
            }
            if (user == null) {
                throw new BizException(SystemConstant.ResponseCode.NOT_LOGIN, "请登录", false);
            }
            //权限不要检查
            if (!authCheck) {
                return true;
            }

            //暂时默认get请求都通过,后续通过资源做标记，获取所有资源去匹配
//        if (request.getMethod().equalsIgnoreCase(HttpMethod.GET.toString())) {
//            return true;
//        }
            List<Long> roleIds = user.getRoleIds();
            if (CollectionUtils.isEmpty(roleIds)) {
                throw new BizException("user role is null");
            }

            for (Long roleId : roleIds) {
                Set<AuthResObj> authResSet = roleAuthResMap.get(roleId);
                if (CollectionUtils.isEmpty(authResSet)) {
                    continue;
                }
                isMatch = authResSet.stream().anyMatch(x -> x != null && StringUtils.equals(x.getUrl(), finalRequestURI));
                if (isMatch) {
                    return true;
                }
                isMatch = authResSet.stream().filter(x -> x != null && x.getUrl().endsWith("*")).anyMatch(x-> finalRequestURI.matches(x.getUrl()));
                if (isMatch) {
                    return true;
                }
            }
            return false;


        } catch (Exception e) {
            throw e;
        }
    }



    @Override
    public void process(ProceedingJoinPoint joinPoint, HttpServletRequest request) {
        String requestURI = request.getRequestURI();

        //现在都在数据中去标记
        UserVo loginUser = userService.getLoginUser(request);

        if(loginUser != null){
            //将当前访问用户放入threadLocal
            UserManager.setLoginUser(loginUser);
            OnlineUser onlineUser = new OnlineUser(loginUser.getId(), loginUser.getUserName());
            OnlineUserManager.setLoginUser(onlineUser);
        }

        boolean checkAuthState = this.checkAuth(requestURI,loginUser);
        if (!checkAuthState) {
            throw new BizException(SystemConstant.ResponseCode.NOT_AUTHORITY, "没有权限", false);
        }

    }

    @Override
    public void clean() {
        OnlineUserManager.clean();
        UserManager.clean();
    }



}
